package edu.uct.tamnd.viettourism.maps;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.NumberPicker;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener;
import com.google.android.gms.maps.GoogleMap.OnInfoWindowClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.Circle;
import com.google.android.gms.maps.model.CircleOptions;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;

import edu.uct.tamnd.urlimageviewhelper.UrlImageViewHelper;
import edu.uct.tamnd.viettourism.MainActivity;
import edu.uct.tamnd.viettourism.R;
import edu.uct.tamnd.viettourism.atm.MapsATM;
import edu.uct.tamnd.viettourism.catlist.TableNameCat;
import edu.uct.tamnd.viettourism.helper.DatabaseHelper;
import edu.uct.tamnd.viettourism.places.TableNamePlaces;
import edu.uct.tamnd.viettourism.placesdetail.PlacesDetail;

public class MapsNew extends FragmentActivity implements LocationListener{

	private GoogleMap mMap;
	private Location location;
	private DatabaseHelper mHelper;
	
	ArrayList<PlacesDistanceItem> placesMarker;
	private String TAG = "Maps";
	
	private Marker mMarkers;
	private Marker currentMarker;
	
	private String id;
	private String address;
	private String name;
	private String image;
	private String latitude;
	private String longitude;
	private String url;
	private String catID;
		
	private int selectedSpin = 0;
	private int selectedNumber = 6;
	
	private LatLngBounds bounds;
	private int distance;
	private String categoryName;
	
	@Override
	protected void onCreate(Bundle arg0) {
		// TODO Aut-generated method stub
		super.onCreate(arg0);
		setContentView(R.layout.maps);
		openDatabase();
		if(mMap!=null){
			mMap.clear();
		}
		
		createCurrentPlacesMarker();
		//currentMarker.showInfoWindow();
		
        Bundle bundle = new Bundle();
        bundle = getIntent().getExtras();
        
        if(bundle != null){
        	bounds = null;
        	final LatLngBounds.Builder builderRoute = new LatLngBounds.Builder();
    		
        	double desLatPlaces = Double.parseDouble(bundle.getString("lat"));
            double desLngPlaces = Double.parseDouble(bundle.getString("lng"));
            String desID = bundle.getString("desID");
            final LatLng des = new LatLng(desLatPlaces, desLngPlaces);
            createMarkerOnMaps(des, desID);
            currentMarker.hideInfoWindow();
            
            url = makeURL(location.getLatitude(), location.getLongitude(), desLatPlaces, desLngPlaces);
    		Log.d("MapsView", "url = " + url);
    		connectAsyncTask cnt = new connectAsyncTask(url);
    		cnt.execute(url);
    		
    		mMap.setOnCameraChangeListener(new OnCameraChangeListener() {

				@Override
				public void onCameraChange(CameraPosition arg0) {
					// TODO Auto-generated method stub
					builderRoute.include(currentMarker.getPosition());
		    		builderRoute.include(des);
					bounds = builderRoute.build();

					int padding = 120; // offset from edges of the map in pixels
					CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
					mMap.animateCamera(cu);
					mMap.setOnCameraChangeListener(null);
				}
			});
    			
        }
        

            mMap.setInfoWindowAdapter(new InfoWindowAdapter() {
    			
    			@Override
    			public View getInfoWindow(Marker marker) {
    				// TODO Auto-generated method stub
    				return null;
    			}
    			
    			@Override
    			public View getInfoContents(Marker marker) {
    				// TODO Auto-generated method stub
    				View v;
    				currentMarker.setTitle("0");
//    		        if(marker == currentMarker){
//    		        	Log.d("Marker", "ID = 0");
//    		        	v = getLayoutInflater().inflate(R.layout.custom_marker_menu, null);
//    		        	Log.d(TAG, "CurrentMarker id = " + marker.getTitle());
//    		        	currentMarker.setSnippet("Click để hiển thị địa danh gần nhất");
//    		        	currentMarker.showInfoWindow();
//    		        	
//    				}
  
    		        	v = getLayoutInflater().inflate(R.layout.custom_marker_item, null);
    		        	Log.d("Marker", "ID != 0");
    		        	Cursor cursor = mHelper.readPlacesMarker(marker.getTitle());
    					
    					if (cursor.moveToFirst()) {
    						do {
    							String mId = cursor.getString(cursor.getColumnIndex(TableNamePlaces.COLUMN_ID));
    							String mAddress = cursor.getString(cursor.getColumnIndex(TableNamePlaces.COLUMN_ADDRESS));
    							String mName = cursor.getString(cursor.getColumnIndex(TableNamePlaces.COLUMN_NAME));
    							String mImage = cursor.getString(cursor.getColumnIndex(TableNamePlaces.COLUMN_IMAGE));
    							
    								try {
    									Log.d(TAG, "ID marker = " + marker.getTitle());
    				    	        	Log.d(TAG, "set data to marker");
    				    	        	Log.d(TAG, "Name = " + mName);

    				    	        	TextView tvNameMarker = (TextView) v.findViewById(R.id.tvNameMarker);
    				    	        	tvNameMarker.setText(mName);
    				    	        	
    				    	        	TextView tvAddressMarker = (TextView) v.findViewById(R.id.tvAddressMarker);
    				    		        tvAddressMarker.setText(mAddress);
    				    		        
    				    		        ImageView imvImageMarker = (ImageView) v.findViewById(R.id.imvImageMarker);
    				    		        Log.d(TAG, "Image Url = " + mImage);
    				    		        UrlImageViewHelper.setUrlDrawable(imvImageMarker, mImage, R.drawable.loading);
    				    		        //imageLoader.DisplayImage(mImage, imvImageMarker);
    				    				
    				    			} catch (Exception e) {
    				    				Log.d(TAG, "Set data error");
    				    			}
    							
    						} while (cursor.moveToNext());
    					}

    		        //
    		        
    		        // Returning the view containing InfoWindow contents
    		        return v;
    		        
    			}
    		});
       	
    		mMap.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
    			
    			@Override
    			public void onInfoWindowClick(Marker marker) {
    				// TODO Auto-generated method stub
    				
    					try {
    						Log.d(TAG, "ID Clicked = " + marker.getTitle());
    						Intent i = new Intent(MapsNew.this, PlacesDetail.class);
    						Bundle bundle = new Bundle();
    						bundle.putInt("placesID", Integer.parseInt(marker.getTitle()));
    						i.putExtras(bundle);
    						if(Integer.parseInt(marker.getTitle()) == 0){
    							createMapDialog();
    							currentMarker.hideInfoWindow();
    						}else{
    							startActivity(i);
    						}
    							
    					} catch (Exception e) {
    						Log.d(TAG, "Khong thay ID " + marker.getTitle());
    					}
    				
    			}
    		});
    		
        		
	}

	public String makeURL (double sourcelat, double sourcelog, double destlat, double destlog ){
        StringBuilder urlString = new StringBuilder();
        urlString.append("http://maps.googleapis.com/maps/api/directions/json");
        urlString.append("?origin=");// from
        urlString.append(Double.toString(sourcelat));
        urlString.append(",");
        urlString.append(Double.toString( sourcelog));
        urlString.append("&destination=");// to
        urlString.append(Double.toString( destlat));
        urlString.append(",");
        urlString.append(Double.toString( destlog));
        urlString.append("&sensor=false&mode=driving&alternatives=true");
        return urlString.toString();
	}
	
	public void drawPath(String result) {

	    try {
	            //Tranform the string into a json object
	           final JSONObject json = new JSONObject(result);
	           JSONArray routeArray = json.getJSONArray("routes");
	           JSONObject routes = routeArray.getJSONObject(0);
	           JSONObject overviewPolylines = routes.getJSONObject("overview_polyline");
	           String encodedString = overviewPolylines.getString("points");
	           List<LatLng> list = decodePoly(encodedString);

	           for(int z = 0; z<list.size()-1;z++){
	                LatLng src= list.get(z);
	                LatLng dest= list.get(z+1);
	                Polyline line = mMap.addPolyline(new PolylineOptions()
	                .add(new LatLng(src.latitude, src.longitude), new LatLng(dest.latitude, dest.longitude))
	                .width(4)
	                .color(Color.BLUE)
	                .geodesic(true));
	                
	            }

	    } 
	    catch (JSONException e) {

	    }
	} 
	private List<LatLng> decodePoly(String encoded) {

	    List<LatLng> poly = new ArrayList<LatLng>();
	    int index = 0, len = encoded.length();
	    int lat = 0, lng = 0;

	    while (index < len) {
	        int b, shift = 0, result = 0;
	        do {
	            b = encoded.charAt(index++) - 63;
	            result |= (b & 0x1f) << shift;
	            shift += 5;
	        } while (b >= 0x20);
	        int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
	        lat += dlat;

	        shift = 0;
	        result = 0;
	        do {
	            b = encoded.charAt(index++) - 63;
	            result |= (b & 0x1f) << shift;
	            shift += 5;
	        } while (b >= 0x20);
	        int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
	        lng += dlng;

	        LatLng p = new LatLng( (((double) lat / 1E5)),
	                 (((double) lng / 1E5) ));
	        poly.add(p);
	    }

	    return poly;
	}
	
	private void createCurrentPlacesMarker(){
		
		int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext());
        if(status!=ConnectionResult.SUCCESS){ // Google Play Services are not available
        	
            int requestCode = 10;
            Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this, requestCode);
            dialog.show();
 
        }else { // Google Play Services are available
 
            // Getting reference to the SupportMapFragment of activity_main.xml
            SupportMapFragment fm = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
 
            // Getting GoogleMap object from the fragment
            mMap = fm.getMap();
            
            // Enabling MyLocation Layer of Google Map
            mMap.setMyLocationEnabled(true);
            try {
                // Getting LocationManager object from System Service LOCATION_SERVICE
                LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
     
                // Creating a criteria object to retrieve provider
                Criteria criteria = new Criteria();
     
                // Getting the name of the best provider
                String provider = locationManager.getBestProvider(criteria, true);
     
                // Getting Current Location
                location = locationManager.getLastKnownLocation(provider);
     
                if(location!=null){
                    onLocationChanged(location);
                }
                locationManager.requestLocationUpdates(provider, 20000, 0, this);
                LatLng currentPoint = new LatLng(location.getLatitude(), location.getLongitude());
                
                mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentPoint, 12));

                currentMarker = mMap.addMarker(new MarkerOptions()
                		.position(currentPoint)
                		.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_from_1))
                		.snippet("Bạn đang đứng ở đây.\n Chạm để tìm địa điểm gần nhất"));
                currentMarker.setTitle("0");
                Log.d("Create Current Marker", "Da set title cho current Marker, title = " + currentMarker.getTitle());
                currentMarker.showInfoWindow();	
                
			} catch (Exception e) {
				Toast.makeText(MapsNew.this, "Lỗi tìm kiếm nhà cung cấp dịch vụ", Toast.LENGTH_SHORT).show();
			}

        }
	}

	private void createPlacesMarker(int dist, String catName) {
		// TODO Auto-generated method stub
		distance = dist;
		categoryName = catName;
		mMap.clear();
		LatLngBounds.Builder builder = new LatLngBounds.Builder();

//	    new Maps_Template(this, location.getLatitude(), location.getLongitude(), dist);
		Circle circle = mMap.addCircle(new CircleOptions()
				.center(new LatLng(location.getLatitude(), location.getLongitude()))
				.radius(dist)
				.fillColor(ColorDrawable.resolveOpacity(0, 70))
				.fillColor(0x40ff0000)
				//.fillColor(0xFFFF0000)
				//.fillColor(0x66339900)
				.strokeColor(Color.BLUE)
				.strokeWidth(5));
	
		createCurrentPlacesMarker();
		builder.include(currentMarker.getPosition());
		bounds = builder.build();
		String categoryID = null;
		Log.d(TAG, "Nhan catName = " + catName);
		Log.d(TAG, "Nhan distance = " + dist);
		if(catName == "Tất cả"){
			categoryID = "0";
		}else{
			Cursor c = mHelper.readIDCategory(catName);
			if (c.moveToFirst()) {
				do {
					categoryID = c.getString(c.getColumnIndex(TableNameCat.COLUMN_ID));
				} while (c.moveToNext());
			}
			Log.d(TAG, "Truy van categoryID = " + categoryID);
		}
		
		Cursor cursor = mHelper.readPlacesDistance();
		if (cursor.moveToFirst()) {
			do {
				id = cursor.getString(cursor.getColumnIndex(TableNamePlaces.COLUMN_ID));
				latitude = cursor.getString(cursor.getColumnIndex(TableNamePlaces.COLUMN_LAT));
				longitude = cursor.getString(cursor.getColumnIndex(TableNamePlaces.COLUMN_LONG));
				catID = cursor.getString(cursor.getColumnIndex(TableNamePlaces.COLUMN_CAT_ID));

				Location placesLocation = new Location(id);
				double lat = 0.0;
				double lng = 0.0;
					
				lat = Double.parseDouble(latitude.trim());
				lng = Double.parseDouble(longitude.trim());
				
				placesLocation.setLatitude(lat);
				placesLocation.setLongitude(lng);
				double distance = location.distanceTo(placesLocation);
				if(distance <= dist && categoryID == "0"){
					LatLng point = new LatLng(placesLocation.getLatitude(), placesLocation.getLongitude());
					Log.d(TAG, "ID = "+ id + "\tDistance = " + distance + "\tLatLng = " + point.latitude + " " + point.longitude);
					createMarkerOnMaps(point, id);
					builder.include(point);
					bounds = builder.build();
				}else{
					if(distance <= dist && Integer.parseInt(catID) == Integer.parseInt(categoryID)){
						LatLng point = new LatLng(placesLocation.getLatitude(), placesLocation.getLongitude());
						Log.d(TAG, "ID = "+ id + "\tDistance = " + distance + "\tLatLng = " + point.latitude + " " + point.longitude);
						createMarkerOnMaps(point, id);
						builder.include(point);
						bounds = builder.build();
						
					}
				}
				
			} while (cursor.moveToNext());
			
		}
		
		int padding = 150; // offset from edges of the map in pixels
		CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
		mMap.animateCamera(cu);
	}

	private void createMarkerOnMaps(LatLng point, String id) {
		// TODO Auto-generated method stub
//		mMap.clear();
		
        // Creating an instance of MarkerOptions to set position
        MarkerOptions markerOptions = new MarkerOptions();

        // Setting position on the MarkerOptions
        markerOptions.position(point);
        
        //Setting icon to marker
        markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_to_1));
        
        // Animating to the currently position
        //mMap.animateCamera(CameraUpdateFactory.newLatLng(point));

        // Adding marker on the GoogleMap
        mMarkers = mMap.addMarker(markerOptions);
        mMarkers.setTitle(id);
        Log.d(TAG, "da set id cho marker");
        // Showing InfoWindow on the GoogleMap

//        marker.showInfoWindow();
        
	}
	
	@Override
	public void onLocationChanged(Location location) {
		// TODO Auto-generated method stub
				 
        // Getting latitude of the current location
        double latitude = location.getLatitude();
 
        // Getting longitude of the current location
        double longitude = location.getLongitude();
 
        // Creating a LatLng object for the current location
        LatLng latLng = new LatLng(latitude, longitude);
 
        // Showing the current location in Google Map
        //mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
 
        // Zoom in the Google Map
        //mMap.animateCamera(CameraUpdateFactory.zoomTo(13));
 
//        Toast.makeText(this, "Lat = " + latitude + ", Long = "+longitude,	Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onProviderDisabled(String provider) {
		// TODO Auto-generated method stub
		Toast.makeText(this, "Enabled new provider " + provider,
                Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onProviderEnabled(String provider) {
		// TODO Auto-generated method stub
		Toast.makeText(this, "Disabled provider " + provider,
                Toast.LENGTH_SHORT).show();

	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		// TODO Auto-generated method stub
		
	}

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
	//	locationManager.removeUpdates(this);
	}

	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
    //    locationManager.requestLocationUpdates(provider, 400, 1, this);

	}
	
	private void openDatabase(){
		mHelper = new DatabaseHelper(this);
		try {
			mHelper.createDatabase();
			Log.d(TAG , "Đã gọi hàm create");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			Log.d("CityList", e.getMessage());
			Toast.makeText(this, "Lỗi db", Toast.LENGTH_LONG).show();
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO Auto-generated method stub
		getMenuInflater().inflate(R.menu.maps_option_menu, menu);
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
		switch (item.getItemId()) {
	      case R.id.satellite:
	            mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
	            return true;
	      case R.id.traffic:
	            mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
	            return true;
	      case R.id.local:
	    	  createMapDialog();
//	    	  	createAlertDialog();
	    	  	return true;
	      default:
	            return super.onOptionsItemSelected(item);
	}	
}
	private void createMapDialog(){
		
		AlertDialog alertDialog;
        LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);
        View v = getLayoutInflater().inflate(R.layout.mapsdialog, null);
        
        ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
        final Spinner spin = (Spinner) v.findViewById(R.id.spinCat);
        spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinnerAdapter.add("Tất cả");
        Cursor cursor = mHelper.readCategory();
		if (cursor.moveToFirst()) {
			do {
				String categoryName = cursor.getString(cursor.getColumnIndex(TableNameCat.COLUMN_NAME));
				spinnerAdapter.add(categoryName);
				
			} while (cursor.moveToNext());
	
		}
        
        spin.setAdapter(spinnerAdapter);
        spin.setSelection(selectedSpin);
                
        final NumberPicker numberDistance = (NumberPicker) v.findViewById(R.id.numberDistance);
        numberDistance.setWrapSelectorWheel(true);
        numberDistance.setMaxValue(20);
        numberDistance.setMinValue(1);
        numberDistance.setValue(selectedNumber);

        Builder builder = new AlertDialog.Builder(this);
        builder.setView(v);
        builder.setIcon(R.drawable.poi_search);
        builder.setTitle("Tìm địa điểm gần nhất");
        
        builder.setPositiveButton("Xong", new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				
					int dist = numberDistance.getValue() * 1000;
					String categoryName = spin.getSelectedItem().toString();
					createPlacesMarker(dist, categoryName);
					selectedSpin = spin.getSelectedItemPosition();
					selectedNumber = numberDistance.getValue();
					dialog.dismiss();
				
				
			}
		});
		builder.setNegativeButton("Hủy", new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				
				dialog.dismiss();
			}
		});

        alertDialog = builder.create();
        alertDialog.show();
        
	}

	private class connectAsyncTask extends AsyncTask<String, Void, String>{
	    private ProgressDialog progressDialog;
	    String url;
	    connectAsyncTask(String urlPass){
	        url = urlPass;
	    }
	    @Override
	    protected void onPreExecute() {
	        // TODO Auto-generated method stub
	        super.onPreExecute();
	        progressDialog = new ProgressDialog(MapsNew.this);
	        progressDialog.setMessage("Đang tìm đường, vui lòng đợi...");
	        progressDialog.setIndeterminate(true);
	        progressDialog.show();
	    }
	    @Override
	    protected String doInBackground(String... params) {
	        JSONParser jParser = new JSONParser();
	        String json = jParser.getJSONFromUrl(url);
	        Log.d("background", "Da lay json = "+json);
	        return json;
	    }
	    @Override
	    protected void onPostExecute(String result) {
	        super.onPostExecute(result);   
	        progressDialog.hide();        
	        if(result!=null){
	        	Log.d("PostExecute json = ", result);
	            drawPath(result);
	        }
	    }
	    
	}
/*	@Override
	public void onBackPressed() {
		// TODO Auto-generated method stub
		Intent i = new Intent(MapsNew.this, MainActivity.class);
		startActivity(i);
	}*/
}